package com.googlecode.perfectable.visuable.parse;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Map;

import com.google.common.base.CharMatcher;

final class ElementStructure {

	static final String IDENTIFIER_ATTRIBUTE_NAME = "id";
	static final String IDENTIFIER_ATTRIBUTE_VALUE_PATTERN = "px-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";

	private final String elementName;
	private final String raw;
	private final Iterable<ElementStructure> children;
	private final Map<String, String> attributes;
	private final boolean hasIdentifier;

	public ElementStructure(String elementName, Map<String, String> attributesMap, boolean hasIdentifier, String raw,
			Iterable<ElementStructure> children) {
		this.elementName = elementName;
		this.attributes = attributesMap;
		this.hasIdentifier = hasIdentifier;
		this.raw = raw;
		this.children = children;
	}

	public Iterable<ElementStructure> children() {
		return this.children;
	}

	@SuppressWarnings("hiding")
	public void assertElementName(String elementName) {
		if(!this.elementName.equals(elementName)) {
			throw new AssertionError("Expected element '" + this.elementName + "' but encountered '" + elementName + "'");
		}
	}

	public void assertAttribute(String name, String value) {
		if(this.hasIdentifier && IDENTIFIER_ATTRIBUTE_NAME.equals(name)) {
			assertTrue(value.matches(IDENTIFIER_ATTRIBUTE_VALUE_PATTERN));
		}
		else {
			String expectedValue = this.attributes.get(name);
			if(expectedValue == null) {
				throw new AssertionError("Missing attribute '" + name + "' with value '" + value + "'");
			}
			else if(!expectedValue.equals(value)) {
				throw new AssertionError("Attribute '" + name + "' has has expected value '" + expectedValue
						+ "' but actual value was '" + value + "'");
			}
			assertEquals(expectedValue, value);
		}
	}

	public void assertRaw(String text) {
		String trimmed = CharMatcher.WHITESPACE.trimFrom(text);
		if(!this.raw.equals(trimmed)) {
			throw new AssertionError("Expected inner text to be '" + this.raw + "' but was '" + trimmed + "'");
		}
	}

	public void assertCleared() {
		// MARK
	}

}
